package com.dominator.utils.pay;

import sun.misc.BASE64Decoder;
import java.io.IOException; 
import java.security.*; 
import java.security.interfaces.RSAPrivateKey; 
import java.security.interfaces.RSAPublicKey; 
import java.security.spec.InvalidKeySpecException; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.security.KeyFactory; 
import java.security.Signature; 
import java.security.spec.X509EncodedKeySpec; 
import java.util.*; 

/** 
 * @Package: honeybee.boluome.util 
 * @Description: 工具类: 
 * @Description: 验证签名方法 
 * @author: boluome 
 * @date: 17/6/3 上午10:52 
 */ 
public class RSAUtils { 

    private static RSAPublicKey rsaPublicKey; 
    private static RSAPrivateKey rsaPrivateKey; 
    private static String ALGORITHM = "SHA256withRSA"; 


    /** 
     * 私钥加密 
     * 
     * @param privateKey 私钥 
     * @param text       明文 
     * @return
     * @throws Exception 
     */ 
    public static String sign(String privateKey, String text) throws Exception { 
        loadPrivateKey(privateKey); 
        Signature signature = Signature.getInstance(ALGORITHM); 
        signature.initSign(rsaPrivateKey); 
        signature.update(text.getBytes()); 
        byte[] result = signature.sign(); 
        return Base64.getEncoder().encodeToString(result); 
    } 

    /** 
     * 公钥加密 
     * 
     * @param publicKey 公钥 
     * @param text      明文 
     * @return
     * @throws Exception 
     */ 
    public static String publicSign(String publicKey, String text) throws Exception { 
        loadPublicKey(publicKey); 
        Signature signature = Signature.getInstance(ALGORITHM); 
        signature.initSign(rsaPrivateKey); 
        signature.update(text.getBytes()); 
        byte[] result = signature.sign(); 
        return Base64.getEncoder().encodeToString(result); 
    } 


    /** 
     * 公钥解密 
     * 
     * @param publicKey 公钥 
     * @param text      明文 
     * @param sign      密文 
     * @return
     * @throws Exception 
     */ 
    public static boolean verify(String publicKey, String text, String sign) throws Exception { 
        loadPublicKey(publicKey); 
        Signature signature = Signature.getInstance(ALGORITHM); 
        signature.initVerify(rsaPublicKey); 
        signature.update(text.getBytes()); 
        byte[] signVar = Base64.getDecoder().decode(sign); 
        boolean flag = signature.verify(signVar); 
        return flag; 
    } 

    /** 
     * 私钥解密 
     * 
     * @param privateKey 私钥 
     * @param text       明文 
     * @param sign       密文 
     * @return
     * @throws Exception 
     */ 
    public static boolean privateVerify(String privateKey, String text, String sign) throws Exception { 
        loadPrivateKey(privateKey); 
        Signature signature = Signature.getInstance(ALGORITHM); 
        signature.initVerify(rsaPublicKey); 
        signature.update(text.getBytes()); 
        byte[] signVar = Base64.getDecoder().decode(sign); 
        boolean flag = signature.verify(signVar); 
        return flag; 
    } 


    /** 
     * 从字符串中加载公钥 
     * 
     * @param publicKeyStr 公钥数据字符串 
     * @throws Exception 加载公钥时产生的异常 
     */ 
    public static void loadPublicKey(String publicKeyStr) { 
        try { 
            BASE64Decoder base64Decoder = new BASE64Decoder(); 
            byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr); 
            KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer); 
            rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); 
        } catch (NoSuchAlgorithmException e) { 
            e.printStackTrace(); 
        } catch (InvalidKeySpecException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } catch (NullPointerException e) { 
            e.printStackTrace(); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 

    /** 
     * 从字符串中加载私钥 
     * 
     * @param privateKeyStr 私钥数据字符串 
     * @throws Exception 加载公钥时产生的异常 
     */ 
    public static void loadPrivateKey(String privateKeyStr) { 
        try { 
            BASE64Decoder base64Decoder = new BASE64Decoder(); 
            byte[] buffer = base64Decoder.decodeBuffer(privateKeyStr); 
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer); 
            KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
            rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec); 
        } catch (NoSuchAlgorithmException e) { 
            e.printStackTrace(); 
        } catch (InvalidKeySpecException e) { 
            e.printStackTrace(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } catch (NullPointerException e) { 
            e.printStackTrace(); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
    } 


    /** 
     * 获取参数名称 key 
     * 
     * @param maps 参数key-value map集合 
     * @return
     */ 
    private static List<String> getParamsName(Map<String, Object> maps) { 
        List<String> paramNames = new ArrayList<>(); 
        for (Map.Entry<String, Object> entry : maps.entrySet()) { 
            paramNames.add(entry.getKey()); 
        } 
        return paramNames; 
    } 

    /** 
     * 参数名称按字典排序 
     * 
     * @param paramNames 参数名称List集合 
     * @return 排序后的参数名称List集合 
     */ 
    private static List<String> lexicographicOrder(List<String> paramNames) { 
        Collections.sort(paramNames); 
        return paramNames; 
    } 

    /** 
     * 拼接排序好的参数名称和参数值 
     * 
     * @param paramNames 排序后的参数名称集合 
     * @param maps       参数key-value map集合 
     * @return String 拼接后的字符串 
     */ 
    private static String splitParams(List<String> paramNames, Map<String, Object> maps) { 
        StringBuilder paramStr = new StringBuilder(); 
        for (String paramName : paramNames) { 
            paramStr.append(paramName); 
            for (Map.Entry<String, Object> entry : maps.entrySet()) { 
                if (paramName.equals(entry.getKey())) { 
                    paramStr.append("=").append(String.valueOf(entry.getValue())).append("&"); 
                } 
            } 
        } 
        return paramStr.toString().substring(0, paramStr.length() - 1); 
    } 


    public static void main(String[] args) throws Exception { 
        String rsaprivateKeyPkcs8 = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKBDdw4HGoYV5CHA\n" + 
                "nebHxzBnxQWZRoZzLgw85rWxyEJbKqsc5UIO2VhBHae11ky2/bmrBgatsEtkZAnz\n" + 
                "AnWtgRwj6UJ2iNmxaSPTvbYdsVhZazO89a7V+RS6Wkao44rlY0pOhxo0F4KpUwPb\n" + 
                "d0JWRrPWeVRAzv8Up1bBYkLeg8tNAgMBAAECgYEAmnwuGWGTmckkXbzU+Q9+3RRK\n" + 
                "gXkc2KHSs41JP8AeMIi8+rEh9almrYInWfEYoF6M+hr39hwborElFcoghts3Zihd\n" + 
                "h/ASf7KIzTHMhw2ZQKpISc65nd7m7gxqNa4dLtg38NRuiWFvdR7h/wdA4ZkgPW+p\n" + 
                "hHMRzfBrHwPfi1ReZIECQQDLhduHepJccHyWSl/VinCsJ7Eecw5QPVGow4ecCuHA\n" + 
                "wxJKmaVReh8yEv658z0uOZq7Z76N0/kbWtwksmyeYXzRAkEAyZYkzUg6Ow8SWynC\n" + 
                "kR/ipU8qDl064WjQzwRBWLXCKAKpQFVuZtJdtc4R2Z7DCgIQwBMRRIF3abrExfHz\n" + 
                "CdWVvQJAARo5hTNZxZxqYFoIyNxWHeidIgAXjMG4RoTAoEzCykuENtk8NwPFVX0a\n" + 
                "2iECLNTtDKTUOGp0h/xnAt/gjL8UcQJAJX+fguw/oMLR+FFRVyumPnf2a8ud61ZT\n" + 
                "GV9CRJ0y67xq/YOm0MurEOmvWlr1DwSJVyF04dhvfSR3/BZgzmCDxQJBAL2NN4+K\n" + 
                "4cqkcayjHnVQJrgSxwqMePWLGD7osXY69FtPST+84xNu/g61BbO/dCJNQXvrYKjS\n" + 
                "yq2q2ayEfKO0VyA="; 

        Map maps = new LinkedHashMap(); 
        maps.put("a", 1); 
        maps.put("c", 23); 
        maps.put("b", "2"); 
        // 自然排序
        String text = splitParams(lexicographicOrder(getParamsName(maps)), maps); 
        System.out.println(text);//a=1&b=2&c=23

        // 私钥加密
        String pass = sign(rsaprivateKeyPkcs8, text); 
        System.out.println("私钥加密后:" + pass);

        String rsapublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgQ3cOBxqGFeQhwJ3mx8cwZ8UF\n" + 
                "mUaGcy4MPOa1schCWyqrHOVCDtlYQR2ntdZMtv25qwYGrbBLZGQJ8wJ1rYEcI+lC\n" + 
                "dojZsWkj0722HbFYWWszvPWu1fkUulpGqOOK5WNKTocaNBeCqVMD23dCVkaz1nlU\n" + 
                "QM7/FKdWwWJC3oPLTQIDAQAB"; 
        // 公钥解密
        System.out.println(verify(rsapublicKey, text, sign(rsaprivateKeyPkcs8, text))); 


        // 公钥加密
        String pass1 = publicSign(rsapublicKey, text); 
        System.out.println("公钥加密后:" + pass1); 

        // 私钥解密
        System.out.println(privateVerify(rsaprivateKeyPkcs8, text, pass1)); 
    } 
}